﻿//====================================================================================================================
//Copyright (c) 2011 IdeaBlade
//====================================================================================================================
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//====================================================================================================================
//The above copyright notice and this permission notice shall be included in all copies or substantial portions of 
//the Software.
//====================================================================================================================
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 
//OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
//OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
//====================================================================================================================

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using Caliburn.Micro;
using HelloWorld.Events;
using IdeaBlade.Validation;

namespace HelloWorld.ViewModel
{
    public class OrderValidationErrorHandler : IHandle<HandleValidationErrors>, INotifyPropertyChanged
    {
        private VerifierResultCollection _errors;

        public OrderValidationErrorHandler(IEventAggregator eventAggregator)
        {
            eventAggregator.Subscribe(this);
        }

        public VerifierResultCollection Errors
        {
            get { return _errors; }
            set
            {
                _errors = value;
                NotifyOnPropertyChanged("Errors");
                NotifyOnPropertyChanged("ErrorMessages");
            }
        }

        public IEnumerable<string> ErrorMessages
        {
            get { return Errors != null ? Errors.Select(e => e.Message) : null; }
        }

        #region IHandle<HandleValidationErrors> Members

        /// <summary>
        /// Handles the message.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Handle(HandleValidationErrors message)
        {
            Errors = message.VerifierResultCollection.Errors;
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        public void Clear()
        {
            if (Errors != null)
            {
                Errors.Clear();
                NotifyOnPropertyChanged("ErrorMessages");
            }
        }

        private void NotifyOnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    // Export this part non-shared. We want to edit in a sandbox
    [Export("OrderEditor"), PartCreationPolicy(CreationPolicy.NonShared)]
    public class OrderDetailViewModel : Screen, IHandle<EditOrderMessage>
    {
        private readonly PerformOrderSave _orderSaveHandler;
        private readonly IWindowManager _windowManager;
        private bool _canceling;

        // Require a new save handler to be injected.
        [ImportingConstructor]
        public OrderDetailViewModel(PerformOrderSave orderSaveHandler, IWindowManager windowManager,
                                    IEventAggregator eventAggregator)
        {
            _orderSaveHandler = orderSaveHandler;
            _windowManager = windowManager;

            ErrorHandler = new OrderValidationErrorHandler(eventAggregator);
        }

        public OrderValidationErrorHandler ErrorHandler { get; set; }

        public Order CurrentOrder
        {
            get { return _orderSaveHandler.CurrentOrder; }
            set
            {
                _orderSaveHandler.CurrentOrder = value;
                NotifyOfPropertyChange(() => CurrentOrder);
            }
        }

        public void Cancel()
        {
            _canceling = true;
            TryClose();
        }

        public void Ok()
        {
            _canceling = false;
            ErrorHandler.Clear();

            _orderSaveHandler.Execute(TryClose,
                                      e => MessageBox.Show(e.Message));
        }

        public override void CanClose(Action<bool> callback)
        {
            if (CurrentOrder.EntityAspect.HasChanges() && _canceling)
            {
                if (MessageBox.Show("There are unsaved changes. Are you sure you want to close?",
                                    "Are you sure?", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                    CurrentOrder.EntityAspect.RejectChanges();
            }

            callback(!CurrentOrder.EntityAspect.HasChanges());
        }

        #region Implementation of IHandle<in EditOrderMessage>

        /// <summary>
        /// Handles the message.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Handle(EditOrderMessage message)
        {
            CurrentOrder = message.CurrentOrder;
            DisplayName = "Editing Order: " + CurrentOrder.OrderID;

            _windowManager.ShowDialog(this);
        }

        #endregion
    }
}